package cn.itcast.hiss.process.activiti.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.itcast.hiss.api.client.HissProcessConstants;
import cn.itcast.hiss.api.client.processdefinition.ProcessDesignModel;
import cn.itcast.hiss.api.client.task.*;
import cn.itcast.hiss.api.server.common.UserInfo;
import cn.itcast.hiss.common.SystemConstant;
import cn.itcast.hiss.common.enums.ProcessStatusEnum;
import cn.itcast.hiss.form.mapper.HissDynamicTableMapper;
import cn.itcast.hiss.form.mapper.HissFormTablesMapper;
import cn.itcast.hiss.form.pojo.HissFormTables;
import cn.itcast.hiss.message.Message;
import cn.itcast.hiss.message.MessageContext;
import cn.itcast.hiss.message.sender.task.*;
import cn.itcast.hiss.process.activiti.mapper.GeBytearrayMapper;
import cn.itcast.hiss.process.activiti.mapper.HiActinstMapper;
import cn.itcast.hiss.process.activiti.mapper.HissProcessFormMapper;
import cn.itcast.hiss.process.activiti.multilnstance.AddMultiInstanceExecutionCmd;
import cn.itcast.hiss.process.activiti.multilnstance.AddSequenceMultiInstanceCmd;
import cn.itcast.hiss.process.activiti.multilnstance.JumpMultiInstanceExecutionCmd;
import cn.itcast.hiss.process.activiti.pojo.HissProcessForm;
import cn.itcast.hiss.process.activiti.service.ActivitiService;
import cn.itcast.hiss.process.activiti.service.CommentService;
import cn.itcast.hiss.process.activiti.service.UserTaskService;
import cn.itcast.hiss.process.activiti.util.VariableUtil;
import cn.itcast.hiss.server.template.HissServerApperanceTemplate;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.DelegationState;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.*;

/*
 * @author miukoo
 * @description 流程办理各功能实现
 * @date 2023/6/3 11:19
 * @version 1.0
 **/
@Slf4j
@Service
@Transactional
public class ActivitiServiceImpl implements ActivitiService {

    @Autowired
    private UserTaskService userTaskService;

    @Autowired
    private HissServerApperanceTemplate hissServerApperanceTemplate;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private CommentService commentService;

    @Autowired
    private HiActinstMapper hiActinstMapper;

    @Autowired
    ManagementService managementService;

    @Autowired
    GeBytearrayMapper geBytearrayMapper;
    @Autowired
    HissProcessFormMapper hissProcessFormMapper;
    @Autowired
    HissFormTablesMapper hissFormTablesMapper;
    @Autowired
    HissDynamicTableMapper hissDynamicTableMapper;

    @Override
    public Set<String> doGetClientUserInfo(DelegateExecution execution, String assignee) {
        Set<String> resClientNames = new HashSet<>();
        Map<String, Object> variables = execution.getVariables();
        //判断是否是客户端变量--如果是客户端变量，那么就提取客户端请求信息
        if (VariableUtil.checkIsClientVariable(assignee)) {
            String[] varList = VariableUtil.getVariables(assignee);
            Object variableValue = variables.get(varList[0]);
            if (ObjectUtil.isNotNull(variableValue)) {
                //说明是流程变量
                if (variableValue.toString().startsWith(SystemConstant.CLIENT_FLAG)) {
                    //TODO 向客户端请求数据--需要获取流程发起人的信息
                    UserInfo userInfo = userTaskService.getBeforeNodeUserInfo(execution);
                    String[] split = variableValue.toString().split("/");
                    userInfo.setCurrentNodeVariable(split[1]);
                    userInfo.setCurrentNodeValue(varList[1]);
                    log.info("当前节点需要的用户信息:{},需要往客户端请求数据", assignee);
                    List<String> name = hissServerApperanceTemplate.getUserInfo(execution.getTenantId(), userInfo);
                    resClientNames.addAll(name);
                } else {
                    //说明是固定的值--不需要请求客户端
                    resClientNames.add(variableValue.toString());
                }
            } else {
                //虽然是变量 但客户端并未上报
                resClientNames.add(assignee);
            }
        } else {
            //不需要请求客户端直接添加
            resClientNames.add(assignee);
        }
        return resClientNames;
    }

    /**
     * 设计文件部署
     *
     * @param message
     * @param messageContext
     */
    @Override
    public void modelToDeploment(Message message, MessageContext messageContext) {
        ProcessDesignModel processDesignModel = (ProcessDesignModel) message.getPalyload();
        Model model = repositoryService.getModel(processDesignModel.getModelId());
        if (model != null) {
            Deployment deploy = modelToDeployment(model, message, messageContext);
            if (deploy == null) {// 发布有错误
                return;
            } else {
                messageContext.addResult("deployId", deploy.getId());
            }
        } else {
            messageContext.addError("msg", "未找到对应的model");
        }
    }

    /**
     * 通过model实现流程的启动
     *
     * @param message
     * @param messageContext
     * @param isInitForm 是否初始化表单数据
     */
    @Override
    public void startByModel(Message message, MessageContext messageContext,boolean isInitForm) {
        ProcessDesignModel processDesignModel = (ProcessDesignModel) message.getPalyload();
        Model model = repositoryService.getModel(processDesignModel.getModelId());
        if (model != null) {
            Deployment deploy = null;
            try{
                deploy = modelToDeployment(model, message, messageContext);
                if (deploy == null) {// 发布有错误
                    return;
                }
            }catch (ActivitiException e){
                e.printStackTrace();
                messageContext.addError("msg", "发布出错："+e.getMessage());
                return;
            }
            List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(deploy.getId())
                    .active()
                    .processDefinitionTenantId(model.getTenantId())
                    .processDefinitionResourceName(HissProcessConstants.PROCESS_RUN_XML).list();
            ProcessDefinition processDefinition = null;
            if(list.size()==1){
                processDefinition = list.get(0);
            }else{
                for (ProcessDefinition definition : list) {
                    BpmnModel bpmnModel = repositoryService.getBpmnModel(definition.getId());
                    if(bpmnModel.getMainProcess().isExecutable()){
                        processDefinition = definition;
                        break;
                    }
                }
            }
            if (processDefinition != null) {
                String title = model.getName();
                HashMap<String, Object> variables = new HashMap<>();
                // 发起人信息作为流程变量
                variables.put(SystemConstant.TASK_VARIABLES_CREATE_USERID, message.getMessageAuth().getCurrentUser().getUserId());
                variables.put(SystemConstant.TASK_VARIABLES_CREATE_USERNAME, message.getMessageAuth().getCurrentUser().getUserName());
                // 存储前端自定义变量
                if (processDesignModel.getVariables() != null) {
                    variables.putAll(processDesignModel.getVariables());
                }

                // 设置用户ID
                Authentication.setAuthenticatedUserId(message.getMessageAuth().getCurrentUser().getUserId());
                ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), processDesignModel.getBusinessKey(), variables);

                // 解析要绑定的表单
                setProcessForm(processInstance.getTenantId(),processInstance.getProcessInstanceId(),processDefinition.getDeploymentId());
                // 添加评论
                String content = String.format("%s发起了流程", message.getMessageAuth().getCurrentUser().getUserName());
                commentService.addComment(processInstance.getProcessInstanceId(), message.getMessageAuth().getCurrentUser().getUserId(), "流程开始", content);

                messageContext.addResultAndCount("processInstanceId", processInstance.getProcessInstanceId());
            } else {
                messageContext.addError("msg", "未找到对应的流程定义");
            }
        } else {
            messageContext.addError("msg", "未找到对应的model");
        }
    }

    /**
     * 插入绑定表单的关系
     * @param tenantId
     * @param processInstanceId
     * @param deploymentId
     */
    private void setProcessForm(String tenantId,String processInstanceId,String deploymentId){
        // 解析并插入流程绑定的表单信息
        List<String> deploymentResourceNames = repositoryService.getDeploymentResourceNames(deploymentId);
        if(deploymentResourceNames.contains(HissProcessConstants.PROCESS_SHOW_CONFIG_JSON)) {
            InputStream resourceAsStream = repositoryService.getResourceAsStream(deploymentId, HissProcessConstants.PROCESS_SHOW_CONFIG_JSON);
            if (resourceAsStream != null) {
                String configJson = IoUtil.readUtf8(resourceAsStream);
                JSONObject jsonObject = JSON.parseObject(configJson);
                JSONArray forms = jsonObject.getJSONArray("forms");
                for (int i = 0; i < forms.size(); i++) {
                    JSONObject form = forms.getJSONObject(i);
                    HissProcessForm hissProcessForm = new HissProcessForm();
                    hissProcessForm.setProcessInstanceId(processInstanceId);
                    hissProcessForm.setFormId(form.getString("id"));
                    hissProcessForm.setFormType(form.getString("type"));
                    hissProcessForm.setNodeId(form.getString("nodeId"));
                    hissProcessForm.setTenantId(tenantId);
                    hissProcessForm.setFormName(form.getString("name"));
                    hissProcessForm.setCreatedTime(new Date());
                    hissProcessFormMapper.insert(hissProcessForm);
                }
            }
        }
    }

    /**
     *  取消的逻辑
     * @param params
     * @param messageContext
     */
    @Override
    public void cancelTask(CancelTaskMessage params, MessageContext messageContext) {
        // 1、判断是否有权限操作：只有流程实例的发起人可以取消，这个需要获得当前登录人和流程的发起人
        CancelTask payload = params.getPalyload();
        if(StrUtil.isNotEmpty(payload.getReason())) {
            String taskId = payload.getTaskId();
            if (StrUtil.isNotEmpty(taskId)) {
                Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
                if(task != null){
                    HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
                    String startUserId = historicProcessInstance.getStartUserId();
                    String userId = params.getMessageAuth().getCurrentUser().getUserId();
                    if(userId.equals(startUserId)){
                        // 2、如果有权限则：
                        // 2.1、添加流程变量：流程被被取消的状态
                        runtimeService.setVariable(task.getExecutionId(),HissProcessConstants.PROCESS_STATUS, ProcessStatusEnum.CANCEL.name());
                        // 2.2、添加流程的操作日志
                        String title = String.format("【%s】%s了流程", params.getMessageAuth().getCurrentUser().getUserName(), payload.getOperatorName());
                        commentService.addComment(task, userId, title, payload.getReason());
                        // 2.3、结束流程（就是删除运行中的流程实例的所有数据）
                        runtimeService.deleteProcessInstance(task.getProcessInstanceId(),payload.getReason());
                        messageContext.addResultAndCount("msg", "任务" + payload.getOperatorName() + "成功");
                        return;
                    }
                }
            }
        }
        messageContext.addError("msg", "无效参数");
    }

    @Override
    public void approveTask(ApproveTaskMessage params, MessageContext messageContext) {
        // 1、判断是否有权限操作：当人任务的办理人是否和当前登录人一样
        ApproveTask palyload = params.getPalyload();
        String taskId = palyload.getTaskId();
        if(StrUtil.isNotEmpty(taskId)){
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            String assignee = task.getAssignee();
            String userId = params.getMessageAuth().getCurrentUser().getUserId();
            if(userId.equals(assignee)){
                // 2、如果有权限操作
                // 2.1、添加操作日志
                String title = String.format("【%s】%s了流程", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName());
                commentService.addComment(task,userId,title,palyload.getReason());
                
                // 把表单数据设置为流程变量
                setFormToVariable(palyload,task.getProcessInstanceId());
                // 2.2、完成当前任务节点
                completeTask(task,palyload.getVariables());

                messageContext.addResultAndCount("msg", "任务" + palyload.getOperatorName() + "成功");
                return;
            }else{
                messageContext.addError("msg","无权限操作");
                return;
            }
        }
        messageContext.addError("msg","无效参数");
    }

    private void setFormToVariable(ApproveTask palyload, String processInstanceId) {
        // 从表单流程关联表中查询流程关联的表单数据
        List<HissProcessForm> hissProcessForms = hissProcessFormMapper.listFormByProcessInstanceId(processInstanceId);
        if(hissProcessForms!=null&& hissProcessForms.size()>0) {// 如果存在，则设置到变量集合中
            Map<String, Object> variables = palyload.getVariables();
            if (variables == null) {
                variables = new HashMap<>();
            }
            HissProcessForm hissProcessForm = hissProcessForms.get(0);
            // 查询表单对应的物理表信息
            HissFormTables table = hissFormTablesMapper.selectMainTable(hissProcessForm.getFormId());
            //从物理表中查询表单数据
            Map<String, Object> data = hissDynamicTableMapper.getData(table, hissProcessForm.getDataId());
            // 将表单数据转为流程变量
            for(String field : data.keySet()){
                if(field.startsWith("hf_")){
                    variables.put(field,data.get(field));
                }
            }
            // 添加变量
            palyload.setVariables(variables);
        }
    }

    @Override
    public void rejectTask(RejectTaskMessage params, MessageContext messageContext) {
        // 1、判断权限：任务办理人和当前登录人是否相同
        RejectTask palyload = params.getPalyload();
        if(StrUtil.isNotEmpty(palyload.getReason()))     {
            String taskId = palyload.getTaskId();
            if (StrUtil.isNotEmpty(taskId)) {
                Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
                if (task != null) {
                    String assignee = task.getAssignee();
                    String userId = params.getMessageAuth().getCurrentUser().getUserId();
                    if (userId.equals(assignee)) {
                        // 2、如果相同：
                        // 2.1、添加不同意日志
                        String title = String.format("【%s】%s了流程", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName());
                        commentService.addComment(task, userId, title, palyload.getReason());
                        // 2.2、判断是否为并行多实例
                        boolean isParallelMultiInstance = isParallelMultiInstance(task.getProcessDefinitionId(),task.getTaskDefinitionKey());
                        if(isParallelMultiInstance){
                            // 2.3、如果是多实例则更新不同意的变量数值并结束当前任务
                            complateTaskButNotDeleteProcess(task, palyload);
                        }else{
                            // 2.3、如果不是多实例则结束当然流程，并记录流程拒绝的状态
                            runtimeService.setVariable(task.getExecutionId(),HissProcessConstants.PROCESS_STATUS,ProcessStatusEnum.REJECT.name());
                            runtimeService.deleteProcessInstance(task.getProcessInstanceId(),palyload.getReason());
                        }
                    }else{
                        messageContext.addError("msg", "无权限操作");
                        return;
                    }
                }
            }

        }
        messageContext.addError("msg","无效参数");
    }

    /**
     * 驳回
     * @param params
     * @param messageContext
     * @param first 是否默认退回流程第一个节点，true 是,false默认是上一个节点，
     */
    @Override
    public void rollBackTask(AnyJumpTaskMessage params, MessageContext messageContext, boolean first) {
        AnyJumpTask palyload = params.getPalyload();
        String taskId = palyload.getTaskId();
        if(StrUtil.isNotEmpty(taskId)) {
            String jumpTaskOrActivityId = palyload.getJumpTaskOrActivityId();
            Task task = taskService.createTaskQuery().taskId(palyload.getTaskId()).singleResult();
            if(task!=null) {
                String assignee = task.getAssignee();
                String userId = params.getMessageAuth().getCurrentUser().getUserId();
                if(assignee.equals(userId)) {
                    BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
                    Process mainProcess = bpmnModel.getMainProcess();
                    //  - 解析驳回节点：解析出发起节点或上一个节点，如果指定了驳回节点则不需要解析
                    jumpTaskOrActivityId = getTargetActivityId(mainProcess, jumpTaskOrActivityId, task, first);
                    //  - 修改下一节点：把当前节点的下一节点动态修改为要驳回的节点
                    FlowNode flowNode = (FlowNode) mainProcess.getFlowElement(task.getTaskDefinitionKey());
                    List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows(); // 备份当前节点的下一节点的线信息，以便后续恢复
                    FlowNode targetNode = (FlowNode) mainProcess.getFlowElement(jumpTaskOrActivityId);
                    List<SequenceFlow> incomingFlows = targetNode.getIncomingFlows();
                    SequenceFlow sequenceFlow = incomingFlows.get(0); // 如果目标任务节点有多个入度，就采用第一个
                    sequenceFlow.setSourceFlowElement(flowNode);
                    sequenceFlow.setSourceRef(flowNode.getId());
                    flowNode.setOutgoingFlows(Arrays.asList(sequenceFlow));
                    //   - 完成当前节点：记录当前节点的操作信息，并完成节点
                    String title = String.format("【%s】%s了流程", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName());
                    commentService.addComment(task, userId, title, palyload.getReason());
                    // 判断当前任务是否为多实例，如果是则使用CMD方式来驳回
                    Object behavior = flowNode.getBehavior();
                    if(behavior instanceof ParallelMultiInstanceBehavior || behavior instanceof SequentialMultiInstanceBehavior) {
                        // 多实例，则调用CMD
                        managementService.executeCommand(new JumpMultiInstanceExecutionCmd(task, sequenceFlow));
                    }else{
                        // 要完成当前所有的任务，以解决网关重复任务的问题
                        completeTask(task, mainProcess);
                    }

                    //   - 恢复节点信息：把之前修改的节点信息恢复成原样
                    flowNode.setOutgoingFlows(outgoingFlows);
                    messageContext.addResultAndCount("msg", "任务" + palyload.getOperatorName() + "成功");
                    return;
                }else{
                    messageContext.addError("msg","无权限操作");
                    return;
                }
            }
        }
        messageContext.addError("msg","无效参数");
    }

    @Override
    public void delegateTask(DelegateTaskMessage params, MessageContext messageContext) {
        // 1、判断权限：任务办理人和当前登录人是否相同
        DelegateTask palyload = params.getPalyload();
        String taskId = palyload.getTaskId();
        if (StrUtil.isNotEmpty(taskId)) {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task != null) {
                String assignee = task.getAssignee();
                String userId = params.getMessageAuth().getCurrentUser().getUserId();
                if (userId.equals(assignee)) {
                    // 2、如果相同：
                    // 2.1、添加委派日志
                    String title = String.format("【%s】%s了流程", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName());
                    String content =String.format("【%s】%s了流程给%s", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName(),palyload.getUserName());
                    commentService.addComment(task, userId, title, content);
                    // 2.2、委派任务
                    taskService.delegateTask(taskId,palyload.getUserId());

                    messageContext.addResultAndCount("msg", "任务" + palyload.getOperatorName() + "成功");
                    return;
                } else {
                    messageContext.addError("msg", "无权限操作");
                    return;
                }
            }
        }
        messageContext.addError("msg","无效参数");
    }

    @Override
    public void claimTask(TaskMessage params, MessageContext messageContext) {
        HissTask palyload = params.getPalyload();
        String taskId = palyload.getTaskId();
        if (StrUtil.isNotEmpty(taskId)) {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task != null) {
                // 权限判断：先判断候选人，再判断候选组。
                // 当前登录人id是否为候选人
                List<IdentityLink> identityLinkList = taskService.getIdentityLinksForTask(task.getId());
                String userId = params.getMessageAuth().getCurrentUser().getUserId();
                boolean isOk = false;
                for (IdentityLink identityLink : identityLinkList) {
                    if(userId.equals(identityLink.getUserId())){
                        isOk = true;
                        break;
                    }
                }
                if(!isOk){ // 从候选组中获取授权
                    String userGroup = params.getMessageAuth().getCurrentUser().getUserGroups();
                    if(StrUtil.isNotEmpty(userGroup)) {
                        for (IdentityLink identityLink : identityLinkList) {
                            if (userGroup.equals(identityLink.getGroupId())) {
                                isOk = true;
                                break;
                            }
                        }
                    }
                }
                if(!isOk){
                    messageContext.addError("msg","无权限操作");
                    return;
                }
                // 添加认领评论
                String comment = String.format("【%s】%s了任务", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName());
                commentService.addComment(task, params.getMessageAuth().getCurrentUser().getUserId(), comment, "");
                // claim认领
                taskService.claim(taskId,userId);
                messageContext.addResultAndCount("msg", "任务" + palyload.getOperatorName() + "成功");
                return;
            }
        }
        messageContext.addError("msg","无效参数");
    }

    @Override
    public void unclaimTask(TaskMessage params, MessageContext messageContext) {
        HissTask palyload = params.getPalyload();
        // 判断权限：当前办理人和当前登录人是否相同
        String taskId = palyload.getTaskId();
        if(StrUtil.isEmpty(taskId)){
            messageContext.addError("msg","无效参数");
            return;
        }
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(task==null){
            messageContext.addError("msg","无效参数");
            return;
        }
        String assignee = task.getAssignee();  // 认领
        String userId = params.getMessageAuth().getCurrentUser().getUserId();
        if(!assignee.equals(userId)){
            messageContext.addError("msg","无权限操作");
            return;
        }
        // 添加评论
        String comment = String.format("【%s】%s了任务", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName());
        commentService.addComment(task, params.getMessageAuth().getCurrentUser().getUserId(), comment, "");
        // 归还
        taskService.unclaim(taskId);
        messageContext.addResultAndCount("msg","任务"+palyload.getOperatorName()+"成功");
    }

    @Override
    public void beforeSignTask(AddExecutionTaskMessage params, MessageContext messageContext) {
        // 判断权限：当前办理人和当前登录人是否相同
        AddExecutionTask palyload = params.getPalyload();
        String taskId = palyload.getTaskId();
        if(StrUtil.isEmpty(taskId)){
            messageContext.addError("msg","无效参数");
            return;
        }
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(task==null){
            messageContext.addError("msg","无效参数");
            return;
        }
        String assignee = task.getAssignee();
        String userId = params.getMessageAuth().getCurrentUser().getUserId();
        if(!assignee.equals(userId)){
            messageContext.addError("msg","无权限操作");
            return;
        }
        // 判断是否为多实例
        boolean isSequentialMultiInstance = isSequentialMultiInstance(task.getProcessDefinitionId(),task.getTaskDefinitionKey());
        if(!isSequentialMultiInstance){
            messageContext.addError("msg",palyload.getOperatorName()+"只支持串行多实例节点");
            return;
        }
        // 添加评论
        String comment = String.format("【%s】%s了人员", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName());
        String content = String.format("%s%s%s", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName(),palyload.getUserName());
        commentService.addComment(task, params.getMessageAuth().getCurrentUser().getUserId(), comment, content);
        // 修改流程变量
        managementService.executeCommand(new AddSequenceMultiInstanceCmd(task,palyload.getUserId()));
        // 结束当前任务
        this.completeTask(task);
        messageContext.addResultAndCount("msg",palyload.getOperatorName()+"成功");
    }

    @Override
    public void doParallelSignTask(AddExecutionTaskMessage params, MessageContext messageContext) {
        // 判断权限：当前办理人和当前登录人是否相同
        AddExecutionTask palyload = params.getPalyload();
        String taskId = palyload.getTaskId();
        if(StrUtil.isEmpty(taskId)){
            messageContext.addError("msg","无效参数");
            return;
        }
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(task==null){
            messageContext.addError("msg","无效参数");
            return;
        }
        String assignee = task.getAssignee();
        String userId = params.getMessageAuth().getCurrentUser().getUserId();
        if(!assignee.equals(userId)){
            messageContext.addError("msg","无权限操作");
            return;
        }
        // 添加评论
        String comment = String.format("【%s】%s了人员", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName());
        String content = String.format("%s%s%s", params.getMessageAuth().getCurrentUser().getUserName(), palyload.getOperatorName(),palyload.getUserName());
        commentService.addComment(task, params.getMessageAuth().getCurrentUser().getUserId(), comment, content);

        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        Process mainProcess = bpmnModel.getMainProcess();
        boolean isParallelMultiInstance = isParallelMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
        if(!isParallelMultiInstance){
            messageContext.addError("msg",palyload.getOperatorName()+"只支持并行多实例节点");
            return;
        }
        // 修改变量&添加节点
        managementService.executeCommand(new AddMultiInstanceExecutionCmd(task, palyload.getUserId(), mainProcess));
        messageContext.addResultAndCount("msg",palyload.getOperatorName()+"成功");
    }

    private boolean isSequentialMultiInstance(String processDefinitionId, String taskDefinitionKey) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        Process mainProcess = bpmnModel.getMainProcess();
        FlowNode flowNode = (org.activiti.bpmn.model.FlowNode) mainProcess.getFlowElement(taskDefinitionKey);
        Object behavior = flowNode.getBehavior();
        return behavior instanceof SequentialMultiInstanceBehavior;
    }

    /**
     * 完成所有的任务：
     * - 如果是当前任务则设置下一个节点问目标节点，并完成
     * - 如果不是则设置下一个节点空，并完成
     * @param task : 当前任务
     * @param mainProcess
     */
    private void completeTask(Task task, Process mainProcess) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
        for(Task tempTask : list){
            if(tempTask.getId().equals(task.getId())){
                // 如果是当前任务则设置下一个节点问目标节点(之前已做好)，并完成
                this.completeTask(task);
            }else{
                // 如果不是则设置下一个节点空，并完成
                FlowNode flowNode = (FlowNode) mainProcess.getFlowElement(tempTask.getTaskDefinitionKey());
                List<SequenceFlow> bak = flowNode.getOutgoingFlows();// 备份
                flowNode.setOutgoingFlows(new ArrayList<>()); // 设置下一个节点，避免当前分支往下继续执行
                this.completeTask(task);
                flowNode.setOutgoingFlows(bak);
                // 为了前端在悬浮提示中，不显示没有人工办理的信息，则需要删除活动实例和任务实例
                historyService.deleteHistoricTaskInstance(tempTask.getId());
                hiActinstMapper.deleteHiActivityInstByTaskId(tempTask.getId());
            }
        }

    }

    private void completeTask(Task task,Map variables){
        if(task.getDelegationState() == DelegationState.PENDING){// 有委派的情况时，需要先完成委派的任务在完成当前任务
            taskService.resolveTask(task.getId());
            taskService.complete(task.getId(),variables);
        }else{
            taskService.complete(task.getId(),variables);
        }
    }

    private void completeTask(Task task){
        if(task.getDelegationState() == DelegationState.PENDING){// 有委派的情况时，需要先完成委派的任务在完成当前任务
            taskService.resolveTask(task.getId());
            taskService.complete(task.getId());
        }else{
            taskService.complete(task.getId());
        }
    }
    /**
     * 解析目标节点
     * @param mainProcess
     * @param jumpTaskOrActivityId 前端目标节点参数
     * @param task 当天任务
     * @param first 是否驳回首节点
     * @return
     */
    private String getTargetActivityId(Process mainProcess, String jumpTaskOrActivityId, Task task, boolean first) {
        if(StrUtil.isEmpty(jumpTaskOrActivityId)) {// 如果需要解析，则解析
            FlowNode flowNode = (FlowNode) mainProcess.getFlowElement(task.getTaskDefinitionKey());
            if(first) {
                // 解析第一个办理节点
                FlowNode parentFlowNode = flowNode;
                FlowNode findNode = flowNode;
                while(true){
                    parentFlowNode = getParentFlowNode(parentFlowNode);
                    // 判断是否是人工办理节点
                    if(parentFlowNode instanceof UserTask){
                        findNode = parentFlowNode;
                    }
                    if(parentFlowNode==null){
                        break;
                    }
                }
                if(findNode!=null){
                    jumpTaskOrActivityId = findNode.getId();
                }
            }else{
                // 解析上一个办理节点：
                FlowNode parentFlowNode = flowNode;
                FlowNode findNode = flowNode;
                while(true){
                    parentFlowNode = getParentFlowNode(parentFlowNode);
                    // 判断是否是人工办理节点
                    if(parentFlowNode instanceof UserTask){
                        findNode = parentFlowNode;
                        break;
                    }
                    if(parentFlowNode==null){
                        break;
                    }
                }
                if(findNode!=null){
                    jumpTaskOrActivityId = findNode.getId();
                }
            }
        }

        // 解决驳回到带有网关的流程中卡死的现象：判断前一个节点是否有网关，如果有则修改驳回节点为网关
        FlowNode flowNode = (FlowNode) mainProcess.getFlowElement(jumpTaskOrActivityId);
        List<SequenceFlow> incomingFlows = flowNode.getIncomingFlows();
        if(incomingFlows!=null && incomingFlows.size()>0){
            for(SequenceFlow incomingFlow : incomingFlows){
                FlowNode sourceFlowElement = (FlowNode)incomingFlow.getSourceFlowElement();
                if(sourceFlowElement instanceof Gateway){
                    jumpTaskOrActivityId = sourceFlowElement.getId();
                }
            }
        }

        return jumpTaskOrActivityId;
    }

    /**
     * 用于获取当前的节点的上一个节点
     * @param currentNode
     * @return
     */
    private FlowNode getParentFlowNode(FlowNode currentNode) {
        List<SequenceFlow> incomingFlows = currentNode.getIncomingFlows();
        // 需求：如果驳回的上一个节点有多个，则默认选中第一个节点
        if(incomingFlows!=null&&incomingFlows.size()>0){
            SequenceFlow sequenceFlow = incomingFlows.get(0);
            return (FlowNode) sequenceFlow.getSourceFlowElement();
        }
        return null;
    }

    private void complateTaskButNotDeleteProcess(Task task, RejectTask payload) {
        Map<String, Object> variables = runtimeService.getVariables(task.getExecutionId());
        //在流程变量中获取拒绝的流程实例数
        Integer complateNumber = (Integer) variables.getOrDefault(SystemConstant.REJECT_INSTANCES,0);
        runtimeService.setVariable(task.getExecutionId(), SystemConstant.REJECT_INSTANCES, ++complateNumber);
        // 审批意见
        this.completeTask(task,payload.getVariables());
    }

    private boolean isParallelMultiInstance(String processDefinitionId, String taskDefinitionKey) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        Process mainProcess = bpmnModel.getMainProcess();
        FlowNode flowNode = (FlowNode) mainProcess.getFlowElement(taskDefinitionKey);
        Object behavior = flowNode.getBehavior();
        return behavior instanceof ParallelMultiInstanceBehavior;
    }


    /**
     * 模型部署
     *
     * @param model
     * @param message
     * @param messageContext
     */
    private Deployment modelToDeployment(Model model, Message message, MessageContext messageContext) {
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                .key(model.getKey())
                .name(model.getName())
                .category(model.getCategory())
                .enableDuplicateFiltering()
                .tenantId(model.getTenantId());
        deploymentBuilder.addBytes(HissProcessConstants.PROCESS_RUN_XML, repositoryService.getModelEditorSource(model.getId()));

        // 是否有表单配置，如果有则给部署信息也保存一份
        String modelConfigJson = geBytearrayMapper.getModelConfigJson(model.getId());
        if (StrUtil.isNotEmpty(modelConfigJson)) {
            deploymentBuilder.addBytes(HissProcessConstants.PROCESS_SHOW_CONFIG_JSON, modelConfigJson.getBytes());
        }

        Deployment deploy = deploymentBuilder.deploy();
        model.setDeploymentId(deploy.getId());
        repositoryService.saveModel(model);
        return deploy;
    }

}
